﻿using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using SystemCenterSoa.ApiLibrary.PermissionsValidation;
using SystemCenterSoa.DtoModel.Common;
using SystemCenterSoa.DtoModel.SystemManager;
using SystemCenterSoa.Service.SystemManager;

namespace SystemCenterSoa.ApiProject.Lib
{
    public class UserTokenVerificationAttribute : Attribute, IActionFilter
    {
        //登录是否登录都写在这里
        private AdminUserService _AdminUserService;
        //操作http上下文的操作，获取token，有一个叫报文的操作
        private IHttpContextAccessor _iHttpContextAccessor;
        public UserTokenVerificationAttribute(AdminUserService AdminUserService, IHttpContextAccessor iHttpContextAccessor)
        {
            _AdminUserService = AdminUserService;
            _iHttpContextAccessor = iHttpContextAccessor;
        }
        public void OnActionExecuted(ActionExecutedContext context)
        {

        }

        /// <summary>
        /// 实现过滤器接口请求执行方法（执行中）请求之前 
        /// </summary> 
        /// <param name="context"></param>
        public void OnActionExecuting(ActionExecutingContext context)
        {
            //从上下文中（context）获取请求的详情，并转化为Microsoft.AspNetCore.Mvc.Controllers.ControllerActionDescriptor
            Microsoft.AspNetCore.Mvc.Controllers.ControllerActionDescriptor cad = ((Microsoft.AspNetCore.Mvc.Controllers.ControllerActionDescriptor)context.ActionDescriptor);
            //从控制器(Controller)中获取是否有AllowAnonymousAttribute 特性, 如果有则不进行验证,直接跳过去
            AllowAnonymousAttribute[] authoritybtnAttribute = (AllowAnonymousAttribute[])cad.ControllerTypeInfo
              .GetCustomAttributes(typeof(AllowAnonymousAttribute), false);
            if (authoritybtnAttribute.Length > 0)
            {
                return;
            }
            //从请求(Action)中获取是否有AllowAnonymousAttribute 特性, 如果有则不进行验证,直接跳过去
            authoritybtnAttribute = (AllowAnonymousAttribute[])
                cad.MethodInfo.GetCustomAttributes(typeof(AllowAnonymousAttribute), false);
            if (authoritybtnAttribute.Length > 0)
            {
                return;
            }


            //第一步获取token，有进行修改，获取token
            string token = AdminUserService.GetTokenInHeader();
            LoginUserDto loginUser = _AdminUserService.GetLoginUserDtoInRedisByToken(token);//获取token
            if (string.IsNullOrEmpty(token) || loginUser == null)//如果token为空 或者 验证不通过, 那说明没有登录
            {
                ResultModel<bool> model = new ResultModel<bool>();//实例

                model.code = ResultCode.NoLogin;
                model.data = false;
                model.mess = "您没有登录!";
                context.Result = new ContentResult()  //短路,  当你需要从当前申请直接跳出,不往下执行是可以利用短路来实现，中断执行，这里是因为token不一样，或者没有
                {
                    Content = JsonConvert.SerializeObject(model)
                };
                return;
            }
            //如果token有值该怎么验证，去bll接着执行啊（旧）
            //获取请求下面是否标注module_code

            //从请求(Action)中获取是否有ApiModuleRelationAttribute 特性, 如果有则不进行验证,直接跳过去（此为复制上方）
            string moduleCode = "";

            ApiModuleRelationAttribute[] amra = (ApiModuleRelationAttribute[])
                cad.MethodInfo.GetCustomAttributes(typeof(ApiModuleRelationAttribute), false);
            if (amra.Length > 0)
            {
                //如果她大于零，把modelcode获取到
                moduleCode = amra[0].ModuleCode;
            }
            //如果action下面没有获取module_code, 就从 controller获取,如果他是空的，没有标注，那就是在一个地方标注了，AdminUserManagerController里的[ApiModuleRelation("diliuge")]这个标注了，那就在这里获取到。如果他为空
            //如果action下面没有获取module_code, 就从 controller获取（老师）
            if (string.IsNullOrWhiteSpace(moduleCode))
            {
                //从这个Mvc.Controllers的描述（ControllerActionDescriptor）里头获取ActionDescriptor的描述，下面的ControllerTypeInfo下面获取他的Attributes 就这个ApiModuleRelationAttribute对话
                amra = (ApiModuleRelationAttribute[])
              //获取Controllers下面的描述，整个描述他的类。获取上下文下面的所有的请求的详情，然后转化为(Microsoft.AspNetCore.Mvc.Controllers.ControllerActionDescriptor)这个类，然后获取下面所有的ControllerTypeInfo的信息，自在GetCustomAttributes获取所有的标注的Attributes然后把它转化为获取ApiModuleRelationAttribute的特性
              //((Microsoft.AspNetCore.Mvc.Controllers.ControllerActionDescriptor)context.ActionDescriptor)【这一段，源代码，只是上面进行了简化，cad是简化之后的】
              cad
              .ControllerTypeInfo
              .GetCustomAttributes(typeof(ApiModuleRelationAttribute), false);
                //你只要知道这个是从请求action下获取标注
                if (amra.Length > 0)
                {
                    moduleCode = amra[0].ModuleCode;
                }
            }
            //如果他这里不为空的话，我需要进行权限验证。如果获取的模块code 不为空, 那说明这个接口需要验证
            if (!string.IsNullOrWhiteSpace(moduleCode))
            {
                //验证登录用户下面有没有这个模块的权限
                bool bl = loginUser.ModelCodes.Contains(moduleCode);
                //如果没有权限，那就短路，您没有权限
                if (!bl)
                {
                    ResultModel<bool> model = new ResultModel<bool>();

                    model.code = ResultCode.NoAuthorization;
                    model.data = false;
                    model.mess = "您没有权限!";
                    context.Result = new ContentResult()  //短路,  当你需要从当前申请直接跳出,不往下执行是可以利用短路来实现，中断执行，这里是因为token不一样，或者没有
                    {
                        Content = JsonConvert.SerializeObject(model)
                    };
                    return;
                }
            }
        }
    }
}
